package com.future;


import java.util.*;

/**
 * Description:
 * 给你一个字符串表达式 s ，请你实现一个基本计算器来计算并返回它的值。
 * 整数除法仅保留整数部分。
 * 示例 1：
 * 输入：s = "3+2*2"
 * 输出：7
 * 示例 2：
 * 输入：s = " 3/2 "
 * 输出：1
 * 示例 3：
 * 输入：s = " 3+5 / 2 "
 * 输出：5
 * 提示：
 * 1 <= s.length <= 3 * 105
 * s 由整数和算符 ('+', '-', '*', '/') 组成，中间由一些空格隔开
 * s 表示一个 有效表达式
 * 表达式中的所有整数都是非负整数，且在范围 [0, 231 - 1] 内
 * 题目数据保证答案是一个 32-binary 整数
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/basic-calculator-ii
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 *
 * @author weiruibai.vendor
 * Date: 2021/11/3 09:36
 */
public class Solution_227 {

    public static void main(String[] args) throws Exception {

        String[] arr = new String[]{"30+54 / 210", "1+1+1", "3/2", "1-1+1", "20-100+80", "3*40-90/20", "3+2*2", "1+1-1"
                , "1+2+3+4+5+6+7+8+9+10"};
        for (String s : arr) {
            if (calculate(s) != calculate_v1(s)) {
                throw new Exception("入参" + s + "。正确结果：" + calculate(s) + "，错误结果结果：" + calculate_v1(s));
            }
        }

        String s = "1+2+3+4+5+6+7+8+9+10";
        System.out.println(calculate_v1(s));
    }

    /**
     * 思路：
     * 1、遇到'/' '*'，记忆住，继续遍历获取，从尾部弹出一个和当前的进行相应的操作
     * 2、遇到'+' '-',直接入队列，并且也把相应符合'+' '-'入队列
     * 3、遍历完成后，处理'+' '-'，注意，必须安装顺序从左到右进行加减操作
     * （eg: 1-1+1，入队为queNum:1->1->1，符号队列queueCha:'-'->'+'，
     * 如果从队尾开始，过程为：queNum:1->2, queNum:-1 ）
     *
     *
     * @param s
     * @return
     */
    public static int calculate_v1(String s) {
        // 存放要计算的数值
        LinkedList<Integer> linkNum = new LinkedList<>();
        Character preSign = null;
        // 存放'+'、'-'字符
        LinkedList<Character> linkChar = new LinkedList<>();
        if (s == null || s.length() == 0) return 0;
        int length = s.toCharArray().length;
        for (int i = 0; i < length; ) {
            char c = s.charAt(i);
            int num = 0;
            if (Character.isDigit(c)) {
                // 这里是重点，如果遍历获取整个数字
                while (i < length && Character.isDigit(s.charAt(i))) {
                    num = num * 10 + (s.charAt(i++) - '0');
                }
                linkNum.add(num);
                // 前一个字符是'/'、'*'，就优先计算
                if (null != preSign && preSign == '/') {
                    int a = linkNum.pollLast();
                    int b = linkNum.pollLast();
                    linkNum.add(b / a);
                    preSign = null;
                } else if (null != preSign && preSign == '*') {
                    Integer a = linkNum.pollLast();
                    Integer b = linkNum.pollLast();
                    linkNum.add(a * b);
                    preSign = null;
                }
            } else { // 非数字字符
                if (' ' != c) {
                    switch (c) {
                        case '/':
                            preSign = '/';
                            break;
                        case '*':
                            preSign = '*';
                            break;
                        default: // '+' '-'的字符入栈
                            linkChar.add(c);
                            break;
                    }
                }
                i++;
            }
        }
        /**
         * 处理+-
         */
        int size = linkChar.size();
        for (int i = 0; size > 0 && i < size; i++) {
            Character pop = linkChar.pollFirst();
            if (pop == '+') {
                linkNum.addFirst(linkNum.pollFirst() + linkNum.pollFirst());
            } else {
                linkNum.addFirst(linkNum.pollFirst() - linkNum.pollFirst());
            }
        }
        return linkNum.poll();
    }

    /**
     * s = "3+2*5+10-8"
     *
     * @param s
     * @return
     */
    public static int calculate(String s) {
        Deque<Integer> stack = new LinkedList<>();
        char preSign = '+';
        int num = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            if (Character.isDigit(s.charAt(i))) {
                num = num * 10 + s.charAt(i) - '0';
            }
            if (!Character.isDigit(s.charAt(i)) && s.charAt(i) != ' ' || i == n - 1) {
                switch (preSign) {
                    case '+':
                        stack.push(num);
                        break;
                    case '-':
                        stack.push(-num);
                        break;
                    case '*':
                        stack.push(stack.pop() * num);
                        break;
                    default:
                        stack.push(stack.pop() / num);
                }
                preSign = s.charAt(i);
                num = 0;
            }
        }
        int ans = 0;
        while (!stack.isEmpty()) {
            ans += stack.pop();
        }
        return ans;
    }
}
